/******************************************************************************
 *
 *  Copyright (C) 2010-2014 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
/******************************************************************************
 *
 *  The original Work has been changed by NXP Semiconductors.
 *
 *  Copyright (C) 2015 NXP Semiconductors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
/******************************************************************************
 *
 *  This is the main implementation file for the NFA EE.
 *
 ******************************************************************************/
#include <string.h>
#include "nfc_api.h"
#include "nfa_sys.h"
#include "nfa_sys_int.h"
#include "nfa_dm_int.h"
#include "nfa_ee_int.h"

extern void nfa_ee_vs_cback (tNFC_VS_EVT event, BT_HDR *p_data);
/*****************************************************************************
**  Global Variables
*****************************************************************************/

/* system manager control block definition */
#if NFA_DYNAMIC_MEMORY == FALSE
tNFA_EE_CB nfa_ee_cb;
#endif

#if(NXP_EXTNS == TRUE)
#ifndef NFA_EE_DISCV_TIMEOUT_VAL
#define NFA_EE_DISCV_TIMEOUT_VAL    4000 //Wait for UICC Init complete.
#endif
#endif

/*****************************************************************************
**  Constants
*****************************************************************************/
static const tNFA_SYS_REG nfa_ee_sys_reg =
{
    nfa_ee_sys_enable,
    nfa_ee_evt_hdlr,
    nfa_ee_sys_disable,
    nfa_ee_proc_nfcc_power_mode
};


#define NFA_EE_NUM_ACTIONS  (NFA_EE_MAX_EVT & 0x00ff)


const tNFA_EE_SM_ACT nfa_ee_actions[] =
{
    /* NFA-EE action function/ internal events */
    nfa_ee_api_discover     ,   /* NFA_EE_API_DISCOVER_EVT      */
    nfa_ee_api_register     ,   /* NFA_EE_API_REGISTER_EVT      */
    nfa_ee_api_deregister   ,   /* NFA_EE_API_DEREGISTER_EVT    */
    nfa_ee_api_mode_set     ,   /* NFA_EE_API_MODE_SET_EVT      */
    nfa_ee_api_set_tech_cfg ,   /* NFA_EE_API_SET_TECH_CFG_EVT  */
    nfa_ee_api_set_proto_cfg,   /* NFA_EE_API_SET_PROTO_CFG_EVT */
    nfa_ee_api_add_aid      ,   /* NFA_EE_API_ADD_AID_EVT       */
    nfa_ee_api_remove_aid   ,   /* NFA_EE_API_REMOVE_AID_EVT    */
    nfa_ee_api_lmrt_size    ,   /* NFA_EE_API_LMRT_SIZE_EVT     */
    nfa_ee_api_update_now   ,   /* NFA_EE_API_UPDATE_NOW_EVT    */
    nfa_ee_api_connect      ,   /* NFA_EE_API_CONNECT_EVT       */
    nfa_ee_api_send_data    ,   /* NFA_EE_API_SEND_DATA_EVT     */
    nfa_ee_api_disconnect   ,   /* NFA_EE_API_DISCONNECT_EVT    */
    nfa_ee_nci_disc_rsp     ,   /* NFA_EE_NCI_DISC_RSP_EVT      */
    nfa_ee_nci_disc_ntf     ,   /* NFA_EE_NCI_DISC_NTF_EVT      */
    nfa_ee_nci_mode_set_rsp ,   /* NFA_EE_NCI_MODE_SET_RSP_EVT  */
    nfa_ee_nci_conn         ,   /* NFA_EE_NCI_CONN_EVT          */
    nfa_ee_nci_conn         ,   /* NFA_EE_NCI_DATA_EVT          */
    nfa_ee_nci_action_ntf   ,   /* NFA_EE_NCI_ACTION_NTF_EVT    */
    nfa_ee_nci_disc_req_ntf ,   /* NFA_EE_NCI_DISC_REQ_NTF_EVT  */
    nfa_ee_nci_wait_rsp     ,   /* NFA_EE_NCI_WAIT_RSP_EVT      */
    nfa_ee_rout_timeout     ,   /* NFA_EE_ROUT_TIMEOUT_EVT      */
    nfa_ee_discv_timeout    ,   /* NFA_EE_DISCV_TIMEOUT_EVT     */
    nfa_ee_lmrt_to_nfcc         /* NFA_EE_CFG_TO_NFCC_EVT       */
};


/*******************************************************************************
**
** Function         nfa_ee_init
**
** Description      Initialize NFA EE control block
**                  register to NFA SYS
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_init (void)
{
    int xx;

    NFA_TRACE_DEBUG0 ("nfa_ee_init ()");

    /* initialize control block */
    memset (&nfa_ee_cb, 0, sizeof (tNFA_EE_CB));
    for (xx = 0; xx < NFA_EE_MAX_EE_SUPPORTED; xx++)
    {
        nfa_ee_cb.ecb[xx].nfcee_id       = NFA_EE_INVALID;
        nfa_ee_cb.ecb[xx].ee_status      = NFC_NFCEE_STATUS_INACTIVE;
    }

    nfa_ee_cb.ecb[NFA_EE_CB_4_DH].ee_status       = NFC_NFCEE_STATUS_ACTIVE;
    nfa_ee_cb.ecb[NFA_EE_CB_4_DH].nfcee_id        = NFC_DH_ID;
#if (NXP_EXTNS == TRUE)
    /*clear the p61 ce*/
    nfa_ee_ce_p61_active = 0;
#endif
    /* register message handler on NFA SYS */
    nfa_sys_register (NFA_ID_EE,  &nfa_ee_sys_reg);
}

/*******************************************************************************
**
** Function         nfa_ee_sys_enable
**
** Description      Enable NFA EE
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_sys_enable (void)
{
    if (nfa_ee_max_ee_cfg)
    {
        /* collect NFCEE information */
        NFC_NfceeDiscover (TRUE);
        nfa_sys_start_timer (&nfa_ee_cb.discv_timer, NFA_EE_DISCV_TIMEOUT_EVT, NFA_EE_DISCV_TIMEOUT_VAL);
    }
    else
    {
        nfa_ee_cb.em_state = NFA_EE_EM_STATE_INIT_DONE;
        nfa_sys_cback_notify_enable_complete (NFA_ID_EE);
    }
}

/*******************************************************************************
**
** Function         nfa_ee_restore_one_ecb
**
** Description      activate the NFCEE and restore the routing when
**                  changing power state from low power mode to full power mode
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_restore_one_ecb (tNFA_EE_ECB *p_cb)
{
    UINT8   mask;
    tNFC_NFCEE_MODE_SET_REVT    rsp;
    tNFA_EE_NCI_MODE_SET        ee_msg;

    NFA_TRACE_DEBUG4 ("nfa_ee_restore_one_ecb () nfcee_id:0x%x, ecb_flags:0x%x ee_status:0x%x ee_old_status: 0x%x", p_cb->nfcee_id, p_cb->ecb_flags, p_cb->ee_status, p_cb->ee_old_status);
    if ((p_cb->nfcee_id != NFA_EE_INVALID) && (p_cb->ee_status & NFA_EE_STATUS_RESTORING) == 0 && (p_cb->ee_old_status & NFA_EE_STATUS_RESTORING) != 0)
    {
        p_cb->ee_old_status &= ~NFA_EE_STATUS_RESTORING;
        mask = nfa_ee_ecb_to_mask(p_cb);
        if (p_cb->ee_status != p_cb->ee_old_status)
        {
            p_cb->ecb_flags   |= NFA_EE_ECB_FLAGS_RESTORE;
            if (p_cb->ee_old_status == NFC_NFCEE_STATUS_ACTIVE)
            {
                NFC_NfceeModeSet (p_cb->nfcee_id, NFC_MODE_ACTIVATE);

                if (nfa_ee_cb.ee_cfged & mask)
                {
                    /* if any routing is configured on this NFCEE. need to mark this NFCEE as changed
                     * to cause the configuration to be sent to NFCC again */
                    p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_ROUTING;
                    p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_VS;
                }
            }
            else
            {
                NFC_NfceeModeSet (p_cb->nfcee_id, NFC_MODE_DEACTIVATE);
            }
        }
        else if (p_cb->ee_status == NFC_NFCEE_STATUS_ACTIVE)
        {
            /* the initial NFCEE status after start up is the same as the current status and it's active:
             * process the same as the host gets activate rsp */
            p_cb->ecb_flags   |= NFA_EE_ECB_FLAGS_RESTORE;
            if (nfa_ee_cb.ee_cfged & mask)
            {
                /* if any routing is configured on this NFCEE. need to mark this NFCEE as changed
                 * to cause the configuration to be sent to NFCC again */
                p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_ROUTING;
                p_cb->ecb_flags |= NFA_EE_ECB_FLAGS_VS;
            }
            rsp.mode        = NFA_EE_MD_ACTIVATE;
            rsp.nfcee_id    = p_cb->nfcee_id;
            rsp.status      = NFA_STATUS_OK;
            ee_msg.p_data   = &rsp;
            nfa_ee_nci_mode_set_rsp ((tNFA_EE_MSG *) &ee_msg);
        }
    }
}

/*******************************************************************************
**
** Function         nfa_ee_proc_nfcc_power_mode
**
** Description      Restore NFA EE sub-module
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_proc_nfcc_power_mode (UINT8 nfcc_power_mode)
{
    UINT32          xx;
    tNFA_EE_ECB     *p_cb;
    BOOLEAN         proc_complete = TRUE;

    NFA_TRACE_DEBUG1 ("nfa_ee_proc_nfcc_power_mode (): nfcc_power_mode=%d", nfcc_power_mode);
    /* if NFCC power state is change to full power */
    if (nfcc_power_mode == NFA_DM_PWR_MODE_FULL)
    {
        if (nfa_ee_max_ee_cfg)
        {
            p_cb = nfa_ee_cb.ecb;
            for (xx = 0; xx < NFA_EE_MAX_EE_SUPPORTED; xx++, p_cb++)
            {
                p_cb->ee_old_status = 0;
                if (xx >= nfa_ee_cb.cur_ee)
                    p_cb->nfcee_id = NFA_EE_INVALID;

                if ((p_cb->nfcee_id != NFA_EE_INVALID) && (p_cb->ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS) && (p_cb->ee_status  != NFA_EE_STATUS_REMOVED))
                {
                    proc_complete       = FALSE;
                    /* NFA_EE_STATUS_RESTORING bit makes sure the ee_status restore to ee_old_status
                     * NFA_EE_STATUS_RESTORING bit is cleared in ee_status at NFCEE_DISCOVER NTF.
                     * NFA_EE_STATUS_RESTORING bit is cleared in ee_old_status at restoring the activate/inactive status after NFCEE_DISCOVER NTF */
                    p_cb->ee_status    |= NFA_EE_STATUS_RESTORING;
                    p_cb->ee_old_status = p_cb->ee_status;
                    /* NFA_EE_FLAGS_RESTORE bit makes sure the routing/nci logical connection is restore to prior to entering low power mode */
                    p_cb->ecb_flags    |= NFA_EE_ECB_FLAGS_RESTORE;
                }
            }
            nfa_ee_cb.em_state          = NFA_EE_EM_STATE_RESTORING;
            nfa_ee_cb.num_ee_expecting  = 0;
            if (nfa_sys_is_register (NFA_ID_HCI))
            {
                nfa_ee_cb.ee_flags   |= NFA_EE_FLAG_WAIT_HCI;
                nfa_ee_cb.ee_flags   |= NFA_EE_FLAG_NOTIFY_HCI;
            }
            NFC_NfceeDiscover (TRUE);
            nfa_sys_start_timer (&nfa_ee_cb.discv_timer, NFA_EE_DISCV_TIMEOUT_EVT, NFA_EE_DISCV_TIMEOUT_VAL);
        }
    }
    else
    {
        nfa_sys_stop_timer (&nfa_ee_cb.timer);
        nfa_sys_stop_timer (&nfa_ee_cb.discv_timer);
        nfa_ee_cb.num_ee_expecting = 0;
    }

    if (proc_complete)
        nfa_sys_cback_notify_nfcc_power_mode_proc_complete (NFA_ID_EE);
}

/*******************************************************************************
**
** Function         nfa_ee_proc_hci_info_cback
**
** Description      HCI initialization complete from power off sleep mode
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_proc_hci_info_cback (void)
{
    UINT32          xx;
    tNFA_EE_ECB     *p_cb;
    tNFA_EE_MSG     data;

    NFA_TRACE_DEBUG0 ("nfa_ee_proc_hci_info_cback ()");
    /* if NFCC power state is change to full power */
    nfa_ee_cb.ee_flags   &= ~NFA_EE_FLAG_WAIT_HCI;

    p_cb = nfa_ee_cb.ecb;
    for (xx = 0; xx < NFA_EE_MAX_EE_SUPPORTED; xx++, p_cb++)
    {
        /* NCI spec says: An NFCEE_DISCOVER_NTF that contains a Protocol type of "HCI Access"
         * SHALL NOT contain any other additional Protocol
         * i.e. check only first supported NFCEE interface is HCI access */
        /* NFA_HCI module handles restoring configurations for HCI access */
        if (p_cb->ee_interface[0] != NFC_NFCEE_INTERFACE_HCI_ACCESS)
        {
            nfa_ee_restore_one_ecb (p_cb);
        }
    }

    if (nfa_ee_restore_ntf_done())
    {
        nfa_ee_check_restore_complete();
        if (nfa_ee_cb.em_state == NFA_EE_EM_STATE_INIT_DONE)
        {
            if (nfa_ee_cb.discv_timer.in_use)
            {
                nfa_sys_stop_timer (&nfa_ee_cb.discv_timer);
                data.hdr.event = NFA_EE_DISCV_TIMEOUT_EVT;
                nfa_ee_evt_hdlr((BT_HDR *)&data);
            }
        }
    }
}

/*******************************************************************************
**
** Function         nfa_ee_proc_evt
**
** Description      Process NFCEE related events from NFC stack
**
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_proc_evt (tNFC_RESPONSE_EVT event, void *p_data)
{
    tNFA_EE_INT_EVT         int_event=0;
    tNFA_EE_NCI_WAIT_RSP    cbk;
    BT_HDR                  *p_hdr;

    switch (event)
    {
    case NFC_NFCEE_DISCOVER_REVT:                /* 4  NFCEE Discover response */
        int_event   = NFA_EE_NCI_DISC_RSP_EVT;
        break;

    case NFC_NFCEE_INFO_REVT:                    /* 5  NFCEE Discover Notification */
        int_event    = NFA_EE_NCI_DISC_NTF_EVT;
        break;

    case NFC_NFCEE_MODE_SET_REVT:                /* 6  NFCEE Mode Set response */
        int_event   = NFA_EE_NCI_MODE_SET_RSP_EVT;
        break;

    case NFC_EE_ACTION_REVT:
        int_event   = NFA_EE_NCI_ACTION_NTF_EVT;
        break;

    case NFC_EE_DISCOVER_REQ_REVT:               /* 10 EE Discover Req notification */
        int_event   = NFA_EE_NCI_DISC_REQ_NTF_EVT;
        break;

    case NFC_SET_ROUTING_REVT:
        int_event   = NFA_EE_NCI_WAIT_RSP_EVT;
        cbk.opcode  = NCI_MSG_RF_SET_ROUTING;
        break;
    }

    NFA_TRACE_DEBUG2 ("nfa_ee_proc_evt: event=0x%02x int_event:0x%x", event, int_event);
    if (int_event)
    {
        p_hdr           = (BT_HDR *) &cbk;
        cbk.hdr.event   = int_event;
        cbk.p_data      = p_data;

        nfa_ee_evt_hdlr (p_hdr);
    }

}

/*******************************************************************************
**
** Function         nfa_ee_ecb_to_mask
**
** Description      Given a ecb, return the bit mask to be used in nfa_ee_cb.ee_cfged
**
** Returns          the bitmask for the given ecb.
**
*******************************************************************************/
UINT8 nfa_ee_ecb_to_mask (tNFA_EE_ECB *p_cb)
{
    UINT8   mask;
    UINT8   index;

    index = (UINT8) (p_cb - nfa_ee_cb.ecb);
    mask  = 1 << index;

    return mask;
}

/*******************************************************************************
**
** Function         nfa_ee_find_ecb
**
** Description      Return the ecb associated with the given nfcee_id
**
** Returns          tNFA_EE_ECB
**
*******************************************************************************/
tNFA_EE_ECB * nfa_ee_find_ecb (UINT8 nfcee_id)
{
    UINT32  xx;
    tNFA_EE_ECB *p_ret = NULL, *p_cb;
    NFA_TRACE_DEBUG0 ("nfa_ee_find_ecb ()");

    if (nfcee_id == NFC_DH_ID)
    {
        p_ret = &nfa_ee_cb.ecb[NFA_EE_CB_4_DH];
    }
    else
    {
        p_cb = nfa_ee_cb.ecb;
        for (xx = 0; xx < NFA_EE_MAX_EE_SUPPORTED; xx++, p_cb++)
        {
            if (nfcee_id == p_cb->nfcee_id)
            {
                p_ret = p_cb;
                break;
            }
        }
    }

    return p_ret;
}

/*******************************************************************************
**
** Function         nfa_ee_find_ecb_by_conn_id
**
** Description      Return the ecb associated with the given connection id
**
** Returns          tNFA_EE_ECB
**
*******************************************************************************/
tNFA_EE_ECB * nfa_ee_find_ecb_by_conn_id (UINT8 conn_id)
{
    UINT32  xx;
    tNFA_EE_ECB *p_ret = NULL, *p_cb;
    NFA_TRACE_DEBUG0 ("nfa_ee_find_ecb_by_conn_id ()");

    p_cb = nfa_ee_cb.ecb;
    for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++)
    {
        if (conn_id == p_cb->conn_id)
        {
            p_ret = p_cb;
            break;
        }
    }

    return p_ret;
}

/*******************************************************************************
**
** Function         nfa_ee_sys_disable
**
** Description      Deregister NFA EE from NFA SYS/DM
**
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_sys_disable (void)
{
    UINT32  xx;
    tNFA_EE_ECB *p_cb;
    tNFA_EE_MSG     msg;

    NFA_TRACE_DEBUG0 ("nfa_ee_sys_disable ()");

    nfa_ee_cb.em_state = NFA_EE_EM_STATE_DISABLED;
    /* report NFA_EE_DEREGISTER_EVT to all registered to EE */
    for (xx = 0; xx < NFA_EE_MAX_CBACKS; xx++)
    {
        if (nfa_ee_cb.p_ee_cback[xx])
        {
            msg.deregister.index     = xx;
            nfa_ee_api_deregister (&msg);
        }
    }

    nfa_ee_cb.num_ee_expecting  = 0;
    p_cb = nfa_ee_cb.ecb;
    for (xx = 0; xx < nfa_ee_cb.cur_ee; xx++, p_cb++)
    {
        if (p_cb->conn_st == NFA_EE_CONN_ST_CONN)
        {
            if (nfa_sys_is_graceful_disable ())
            {
                /* Disconnect NCI connection on graceful shutdown */
                msg.disconnect.p_cb = p_cb;
                nfa_ee_api_disconnect (&msg);
                nfa_ee_cb.num_ee_expecting++;
            }
            else
            {
                /* fake NFA_EE_DISCONNECT_EVT on ungraceful shutdown */
                msg.conn.conn_id    = p_cb->conn_id;
                msg.conn.event      = NFC_CONN_CLOSE_CEVT;
                nfa_ee_nci_conn (&msg);
            }
        }
    }

    if (nfa_ee_cb.num_ee_expecting)
    {
        nfa_ee_cb.ee_flags |= NFA_EE_FLAG_WAIT_DISCONN;
        nfa_ee_cb.em_state  = NFA_EE_EM_STATE_DISABLING;
    }


    nfa_sys_stop_timer (&nfa_ee_cb.timer);
    nfa_sys_stop_timer (&nfa_ee_cb.discv_timer);

    /* If Application initiated NFCEE discovery, fake/report the event */
    nfa_ee_report_disc_done (FALSE);

    /* deregister message handler on NFA SYS */
    if (nfa_ee_cb.em_state == NFA_EE_EM_STATE_DISABLED)
        nfa_sys_deregister (NFA_ID_EE);

}

/*******************************************************************************
**
** Function         nfa_ee_check_disable
**
** Description      Check if it is safe to move to disabled state
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_check_disable (void)
{
    if (!(nfa_ee_cb.ee_flags & NFA_EE_FLAG_WAIT_DISCONN))
    {
        nfa_ee_cb.em_state = NFA_EE_EM_STATE_DISABLED;
        nfa_sys_deregister (NFA_ID_EE);
    }
}
/*******************************************************************************
**
** Function         nfa_ee_reg_cback_enable_done
**
** Description      Allow a module to register to EE to be notified when NFA-EE
**                  finishes enable process
**
** Returns          None
**
*******************************************************************************/
void nfa_ee_reg_cback_enable_done (tNFA_EE_ENABLE_DONE_CBACK *p_cback)
{
    nfa_ee_cb.p_enable_cback = p_cback;
}

#if (BT_TRACE_VERBOSE == TRUE)
/*******************************************************************************
**
** Function         nfa_ee_sm_st_2_str
**
** Description      convert nfa-ee state to string
**
*******************************************************************************/
static char *nfa_ee_sm_st_2_str (UINT8 state)
{
    switch (state)
    {
    case NFA_EE_EM_STATE_INIT:
        return "INIT";

    case NFA_EE_EM_STATE_INIT_DONE:
        return "INIT_DONE";

    case NFA_EE_EM_STATE_RESTORING:
        return "RESTORING";

    case NFA_EE_EM_STATE_DISABLING:
        return "DISABLING";

    case NFA_EE_EM_STATE_DISABLED:
        return "DISABLED";

    default:
        return "Unknown";
    }
}

/*******************************************************************************
**
** Function         nfa_ee_sm_evt_2_str
**
** Description      convert nfa-ee evt to string
**
*******************************************************************************/
static char *nfa_ee_sm_evt_2_str (UINT16 event)
{
    switch (event)
    {
    case NFA_EE_API_DISCOVER_EVT:
        return "API_DISCOVER";
    case NFA_EE_API_REGISTER_EVT:
        return "API_REGISTER";
    case NFA_EE_API_DEREGISTER_EVT:
        return "API_DEREGISTER";
    case NFA_EE_API_MODE_SET_EVT:
        return "API_MODE_SET";
    case NFA_EE_API_SET_TECH_CFG_EVT:
        return "API_SET_TECH_CFG";
    case NFA_EE_API_SET_PROTO_CFG_EVT:
        return "API_SET_PROTO_CFG";
    case NFA_EE_API_ADD_AID_EVT:
        return "API_ADD_AID";
    case NFA_EE_API_REMOVE_AID_EVT:
        return "API_REMOVE_AID";
    case NFA_EE_API_LMRT_SIZE_EVT:
        return "API_LMRT_SIZE";
    case NFA_EE_API_UPDATE_NOW_EVT:
        return "API_UPDATE_NOW";
    case NFA_EE_API_CONNECT_EVT:
        return "API_CONNECT";
    case NFA_EE_API_SEND_DATA_EVT:
        return "API_SEND_DATA";
    case NFA_EE_API_DISCONNECT_EVT:
        return "API_DISCONNECT";
    case NFA_EE_NCI_DISC_RSP_EVT:
        return "NCI_DISC_RSP";
    case NFA_EE_NCI_DISC_NTF_EVT:
        return "NCI_DISC_NTF";
    case NFA_EE_NCI_MODE_SET_RSP_EVT:
        return "NCI_MODE_SET";
    case NFA_EE_NCI_CONN_EVT:
        return "NCI_CONN";
    case NFA_EE_NCI_DATA_EVT:
        return "NCI_DATA";
    case NFA_EE_NCI_ACTION_NTF_EVT:
        return "NCI_ACTION";
    case NFA_EE_NCI_DISC_REQ_NTF_EVT:
        return "NCI_DISC_REQ";
    case NFA_EE_NCI_WAIT_RSP_EVT:
        return "NCI_WAIT_RSP";
    case NFA_EE_ROUT_TIMEOUT_EVT:
        return "ROUT_TIMEOUT";
    case NFA_EE_DISCV_TIMEOUT_EVT:
        return "NFA_EE_DISCV_TIMEOUT_EVT";
    case NFA_EE_CFG_TO_NFCC_EVT:
        return "CFG_TO_NFCC";
    default:
        return "Unknown";
    }
}
#endif /* BT_TRACE_VERBOSE */

/*******************************************************************************
**
** Function         nfa_ee_evt_hdlr
**
** Description      Processing event for NFA EE
**
**
** Returns          TRUE if p_msg needs to be deallocated
**
*******************************************************************************/
BOOLEAN nfa_ee_evt_hdlr (BT_HDR *p_msg)
{
    tNFA_EE_MSG *p_evt_data = (tNFA_EE_MSG *) p_msg;
    UINT16  event = p_msg->event & 0x00ff;
    BOOLEAN act = FALSE;

#if (BT_TRACE_VERBOSE == TRUE)
    NFA_TRACE_DEBUG4 ("nfa_ee_evt_hdlr (): Event %s(0x%02x), State: %s(%d)",
        nfa_ee_sm_evt_2_str (p_evt_data->hdr.event), p_evt_data->hdr.event,
        nfa_ee_sm_st_2_str (nfa_ee_cb.em_state), nfa_ee_cb.em_state);
#else
    NFA_TRACE_DEBUG2 ("nfa_ee_evt_hdlr (): Event 0x%02x, State: %d", p_evt_data->hdr.event, nfa_ee_cb.em_state);
#endif

#if(NXP_EXTNS == TRUE)
    /*This is required to receive Reader Over SWP event*/
    if(p_evt_data->hdr.event == NFA_EE_NCI_DISC_NTF_EVT)
    {
        NFA_TRACE_DEBUG0("recived dis_ntf; stopping timer");
        nfa_sys_stop_timer(&nfa_ee_cb.discv_timer);
    }
#endif

    switch (nfa_ee_cb.em_state)
    {
    case NFA_EE_EM_STATE_INIT_DONE:
    case NFA_EE_EM_STATE_RESTORING:
        act = TRUE;
        break;
    case NFA_EE_EM_STATE_INIT:
        if ((p_msg->event == NFA_EE_NCI_DISC_NTF_EVT) || (p_msg->event == NFA_EE_NCI_DISC_RSP_EVT))
            act = TRUE;
        break;
    case NFA_EE_EM_STATE_DISABLING:
        if (p_msg->event == NFA_EE_NCI_CONN_EVT)
            act = TRUE;
        break;
    }
    if (act)
    {
        if (event < NFA_EE_NUM_ACTIONS)
        {
            (*nfa_ee_actions[event]) (p_evt_data);
        }
    }
    else
    {
        /* if the data event is not handled by action function, free the data packet */
        if (p_msg->event == NFA_EE_NCI_DATA_EVT)
            GKI_freebuf (p_evt_data->conn.p_data);
    }

    return TRUE;
}
